package com.study.commomThirdPartyTechnologies.common.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;

@Component
@Slf4j
public class OkHttpClientUtil {

    @Autowired
    @Qualifier("commonOkHttp")
    OkHttpClient okHttpClient;

    public String getForm(String url, Map<String, String> params) {
        Map<String, String> headers = Maps.newHashMap();
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);

        return get(url, headers, params);
    }

    public <T> T getForm(String url, Map<String, String> params, Class<T> clazz) {
        String form = getForm(url, params);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }

    public <T> T getForm(String url, Map<String, String> headers, Map<String, String> params, Class<T> clazz) {
        String form = getForm(url, headers, params);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }

    public String getForm(String url, Map<String, String> headers, Map<String, String> params) {
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        return get(url, headers, params);
    }

    public String deleteForm(String url, Map<String, String> headers, Map<String, String> params) {
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        return delete(url, headers, params);
    }

    public <T> T deleteForm(String url, Map<String, String> headers, Map<String, String> params, Class<T> clazz) {
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        String s = delete(url, headers, params);
        T t = JSONObject.parseObject(s, clazz);
        return t;
    }

    public String postForm(String url, Map<String, String> params) {
        return postForm(url, Maps.newHashMap(), params);
    }

    public String postForm(String url, Map<String, String> headers, Map<String, String> params) {
        FormBody.Builder builder = new FormBody.Builder();
        for (Map.Entry<String, String> param : params.entrySet()) {
            builder.add(param.getKey(), param.getValue());
        }
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        return requestByMethod(url, headers, builder.build(), HttpMethod.POST.name());
    }


    public <T> T postForm(String url, Map<String, String> params, Class<T> clazz) {
        String form = postForm(url, params);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }


    public <T> T postForm(String url, Map<String, String> headers, Map<String, String> params, Class<T> clazz) {
        String form = postForm(url, headers, params);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }

    public String postJson(String url, String paramJson) {
        return postJson(url, Maps.newHashMap(), paramJson);
    }

    public <T> T postJson(String url, String paramJson, Class<T> clazz) {
        String form = postJson(url, paramJson);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }


    public <T> T postJson(String url, Map<String, String> headers, String paramJson, Class<T> clazz) {
        String form = postJson(url, headers, paramJson);
        T t = JSONObject.parseObject(form, clazz);
        return t;
    }

    public String postJson(String url, Map<String, String> headers, String paramJson) {
        headers.put("Content-Type", org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE);
        MediaType mediaType = MediaType.parse(org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE);
        RequestBody body = RequestBody.create(mediaType, paramJson);
        return requestByMethod(url, headers, body, HttpMethod.POST.name());
    }

    public String requestByMethod(String url, Map<String, String> headers, RequestBody body, String method) {
        Request request = (new Request.Builder())
                .url(url)
                .method(method, body)
                .headers(Headers.of(headers))
                .addHeader("Accept", "application/json")
                .build();
        try {
            log.info("[requestByMethod start]: url:{} headers:{}", url, headers);
            Response response = okHttpClient.newCall(request).execute();
            checkHttpStatus(response);
            String res = response.body().string();
            log.info("[requestByMethod end]: url:{} res:{}", url, res);
            return res;
        } catch (IOException e) {
            log.info("[requestByMethod error]: e:{}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    private <T> void checkHttpStatus(Response response) {
        if (response == null || response.body() == null) {
            String format = StrUtil.format("[checkHttpStatus error]");
            throw new RuntimeException(format);
        }
    }

    private String get(String url, Map<String, String> headers, Map<String, String> params) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if (!CollectionUtils.isEmpty(params)) {
            for (Map.Entry<String, String> param : params.entrySet()) {
                urlBuilder.addQueryParameter(param.getKey(), param.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .method("GET", (RequestBody) null)
                .headers(Headers.of(headers))
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            checkHttpStatus(response);

            return response.body().string();
        } catch (IOException e) {
            log.error("[get error]: e:{}", e);
            throw new RuntimeException(e.getMessage());
        }
    }

    private String delete(String url, Map<String, String> headers, Map<String, String> params) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if (!CollectionUtils.isEmpty(params)) {
            for (Map.Entry<String, String> param : params.entrySet()) {
                urlBuilder.addQueryParameter(param.getKey(), param.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .method("DELETE", (RequestBody) null)
                .headers(Headers.of(headers))
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            checkHttpStatus(response);
            return response.body().string();
        } catch (IOException e) {
            log.error("[get error]: e:{}", e);
            throw new RuntimeException(e.getMessage());
        }
    }

}
